package net.pimpas.web.jsf.components.validators;

import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;
import javax.faces.validator.Validator;
import javax.faces.webapp.ValidatorTag;
import javax.servlet.jsp.JspException;

import net.pimpas.logging.serviceprovider.LoggingServiceProvider;
import net.pimpas.logging.serviceprovider.LoggingServiceProviderFactoryImpl;
import net.pimpas.resourcebundle.exception.MessageKeyNotFoundException;
import net.pimpas.resourcebundle.exception.ResourceBundleNotFoundException;
import net.pimpas.resourcebundle.serviceprovider.ResourceBundleServiceProvider;
import net.pimpas.resourcebundle.serviceprovider.ResourceBundleServiceProviderFactoryImpl;
import net.pimpas.resourcebundle.serviceprovider.ResourceBundleServiceProviderType;
import net.pimpas.web.jsf.components.validators.exception.PimpasValidatorTagException;
import net.pimpas.web.jsf.util.ComponentUtils;

public abstract class PimpasValidatorTag<T extends PimpasValidator> extends ValidatorTag {

	private static final long serialVersionUID = -8791276845353899591L;
	private String bundleHandler;
	
	private static final LoggingServiceProvider logger = 
		LoggingServiceProviderFactoryImpl.getLoggingServiceProvider(PimpasValidatorTag.class);
	private static final ResourceBundleServiceProvider bundle = 
		ResourceBundleServiceProviderFactoryImpl.getResourceBundleServiceProvider();
	
	@SuppressWarnings("unchecked")
	@Override
	protected Validator createValidator() throws JspException {
		boolean local = false;
		if(this.getBundleHandler() == null || "".equals(this.getBundleHandler())) local = true;
		else	
			if(!ComponentUtils.isOnlyValueBinding(this.getBundleHandler())) {
				String message = null;
				try {
					message = bundle.getMessage(PimpasValidator.class, "validatorAttIncorrectValue",
							ResourceBundleServiceProviderType.ERROR, "bundleHandler", this.getId(), "value binding");
					throw new JspException(message);
				} catch (ResourceBundleNotFoundException e) {
				} catch (MessageKeyNotFoundException e) {
				}
			}
		Object object = null;
		if(!local) {
			ValueBinding vb = FacesContext.getCurrentInstance().getApplication().createValueBinding(this.getBundleHandler());
			object = vb.getValue(FacesContext.getCurrentInstance());
			if(object == null) {
				// use default
				object = this;
				try {
					logger.info(bundle.getMessage(PimpasValidator.class, "bundleHandlerNotFound",
							ResourceBundleServiceProviderType.INFO, this.getClass().getSimpleName()));
				} catch (ResourceBundleNotFoundException e) {
				} catch (MessageKeyNotFoundException e) {
				}
			}
		} else {
			// use default
			object = this;
			try {
				logger.info(bundle.getMessage(PimpasValidator.class, "bundleHandlerNotFound",
						ResourceBundleServiceProviderType.INFO, this.getClass().getSimpleName()));
			} catch (ResourceBundleNotFoundException e) {
			} catch (MessageKeyNotFoundException e) {
			}
		}
		
		Class clazz = object.getClass();
		this.setValidatorId(this.getValidatorID());
		T validator =  (T) super.createValidator() ;
		validator.setBundleHandler(clazz);
		try {
			this.validate(FacesContext.getCurrentInstance(), validator);
		} catch(PimpasValidatorTagException e) {
			throw new JspException(e);
		}
		
		return validator;
	}
	
	public abstract String getValidatorID( );
	
	public ResourceBundleServiceProvider getBundle( ) {
		return bundle;
	}
	
	
	protected void validate( FacesContext context, T validator ) throws PimpasValidatorTagException {
		
	}

	public String getBundleHandler() {
		return bundleHandler;
	}

	public void setBundleHandler(String bundleHandler) {
		this.bundleHandler = bundleHandler;
	}
}